A maioria dos tutoriais do Laravel fornece código funcional e o orienta. Isso é bom para ver como as peças se encaixam, mas não ensina muito sobre o que acontece quando você deixa um campo em branco, digita o nome errado do parâmetro ou hesita antes de executar um comando no qual ainda não confia totalmente.
Então, em vez de seguir um tutorial, criei algo pequeno do zero: o Tiny Journal, um aplicativo de registro no diário de uma única página. Escreva uma entrada, leia-a, edite-a, exclua-a. Sem autenticação, sem tags, sem pesquisa. Pequeno o suficiente para terminar em um fim de semana, grande o suficiente para atingir conceitos reais do Laravel ao longo do caminho.
Esse é o processo que segui, na ordem, inclusive as peças que quebraram.
O que você precisa
- Conhecimento básico de PHP (variáveis, funções, arrays)
- Uma instalação local do Laravel
- Familiaridade com MVC em nÃvel conceitual, você não precisa de experiência especÃfica em Laravel
Etapa 1: o modelo e a migração
Tudo começa com um modelo, Entrye uma migração:
php artisan make:model Entry -m
Schema::create('entries', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('content');
$table->timestamps();
});
php artisan migrate
Dois campos, title e contentambos obrigatórios no nÃvel do banco de dados. Esse último detalhe importa mais do que deveria, é a razão pela qual o primeiro bug real neste projeto existiu.
Etapa 2: leitura de entradas (index e show)
Com a tabela instalada, o primeiro recurso funcional era apenas exibir entradas:
public function index()
{
$entries = Entry::all();
return view('entries.index', ('entries' => $entries));
}
public function show(Entry $entry)
{
return view('entries.show', ('entry' => $entry));
}
show() já usa vinculação de modelo de rota aqui, o Laravel corresponde ao {entry} espaço reservado na rota para o Entry $entry parâmetro e busca o registro automaticamente, sem manual find() necessário. Só percebi isso totalmente mais tarde, quando tentei escrever edit() percorri o longo caminho e percebi a incompatibilidade (mais sobre isso abaixo).
Etapa 3: Criação de entradas (create e store)
public function create()
{
return view('entries.create');
}
public function store(Request $request)
{
$entry = new Entry();
$entry->title = $request->title;
$entry->content = $request->content;
$entry->save();
return redirect('/');
}
Isso funcionou até eu enviar o formulário com o tÃtulo deixado em branco. O que voltou foi um erro de banco de dados de página inteira, uma violação de restrição NOT NULL, direto da migração na Etapa 1. O banco de dados estava aplicando corretamente uma regra que eu mesmo escrevi, apenas no pior lugar possÃvel, após o formulário já ter sido enviado, com um rastreamento de pilha em vez de uma frase na qual o usuário poderia agir.
A correção é a validação, chamada antes que qualquer coisa toque o banco de dados:
public function store(Request $request)
{
$request->validate((
'title' => 'required',
'content' => 'required',
));
$entry = new Entry();
$entry->title = $request->title;
$entry->content = $request->content;
$entry->save();
return redirect('/');
}
validate() permite a solicitação ou a interrompe e redireciona de volta para o formulário automaticamente. Para realmente exibir o erro, faça um loop no saco de erros do Laravel na visualização:
@foreach ($errors->all() as $error)
{{ $error }}
@endforeach
Uma pegadinha: $errors não é um array simples que você pode percorrer diretamente, é um MessageBage você precisa ->all() para extrair as sequências de mensagens. Loop $errors em si e você não obtém nada, nenhum erro, nenhuma falha, apenas silêncio.
Etapa 4: Editando entradas (edit e update)
public function edit($id)
{
$entry = Entry::find($id);
return view('entries.edit', ('entry' => $entry));
}
public function update(Request $request, Entry $entry)
{
$entry->title = $request->input('title');
$entry->content = $request->input('content');
$entry->save();
return redirect('/');
}
Duas coisas surgiram aqui. Primeiro, a mesma falha do tÃtulo em branco da Etapa 3 ainda era possÃvel update()pois ainda não tinha validação. A correção é idêntica, apenas sequenciada corretamente, valide antes de escrever qualquer coisa $entrynão depois:
public function update(Request $request, Entry $entry)
{
$request->validate((
'title' => 'required',
'content' => 'required',
));
$entry->title = $request->input('title');
$entry->content = $request->input('content');
$entry->save();
return redirect('/');
}
Em segundo lugar, comparando edit() e update() clique lado a lado para vincular o modelo de rota. update() usa Entry $entry e nunca liga find(). edit() ainda usei o manual $id + Entry::find($id) padrão. Uma vez que eu reescrevi edit() para combinar:
public function edit(Entry $entry)
{
return view('entries.edit', ('entry' => $entry));
}
A regra tornou-se óbvia: a vinculação do modelo de rota funciona sempre que a URL contém um ID apontando para algo que já existe. Isso é verdade para edit, updatee destroy. Nunca é verdade para store ou indexnão há nenhum registro especÃfico nesses URLs para vincular em primeiro lugar.
Etapa 5: um bug mais sutil, entrada antiga
Depois de adicionar a validação, algo parecia certo pelo motivo errado. Digite um tÃtulo real, deixe o conteúdo em branco e envie. A página é recarregada e o campo de tÃtulo ainda mostra o que digitei. Parecia uma entrada antiga funcionando. Não foi, o tÃtulo era apenas $entry->titleintocado, porque a validação interrompeu o salvamento antes que algo chegasse ao banco de dados.
A correção real é o old() ajudante:
title) }}">
old('title', $entry->title) verifica primeiro as entradas restantes de um envio com falha. Se existir, ele vence. Se a página for aberta do zero, ela retornará ao valor armazenado da entrada. O verdadeiro teste: mudar o tÃtulo, apagar o conteúdo, enviar. Se estiver conectado corretamente, o tÃtulo editado sobreviverá à viagem de ida e volta em vez de ser revertido.
Etapa 6: excluir entradas e reunir seis rotas em uma
public function destroy(Entry $entry)
{
$entry->delete();
return redirect('/');
}
A essa altura, eu tinha seis rotas escritas à mão, uma por ação:
Route::get('/entries', (EntryController::class, 'index'));
Route::get('/entries/create', (EntryController::class, 'create'));
Route::post('/entries', (EntryController::class, 'store'));
Route::get('/entries/{entry}/edit', (EntryController::class, 'edit'));
Route::put('/entries/{entry}', (EntryController::class, 'update'));
Route::delete('/entries/{entry}', (EntryController::class, 'destroy'));
Laravel recolhe todos os seis em uma linha:
Route::resource('entries', EntryController::class);
Fiquei pensando nisso por mais tempo do que deveria, convencido de que a mudança forçaria mudanças em outros lugares. Não aconteceu. O controlador não mudou nada, apenas o arquivo de rotas mudou. Route::resource() não está gerando um novo comportamento, são as mesmas seis rotas, os mesmos nomes, os mesmos verbos, pré-montados.
Etapa 7: Limpeza com layout compartilhado
Quando tudo funcionou, todas as quatro visualizações (index, create, edit, show) tinham seu próprio completo , e “ tags, copiadas e coladas quatro vezes. Um layout compartilhado corrige isso:
{{-- resources/views/layouts/app.blade.php --}}
Tiny Journal
@yield('content')
Cada visualização é reduzida apenas ao seu conteúdo exclusivo:
{{-- resources/views/entries/index.blade.php --}}
@extends('layouts.app')
@section('content')
@foreach ($entries as $entry)
{{ $entry->title }}
{{ $entry->content }}
id }}">View
id }}/edit">Edit
@endforeach
@endsection
Adicione um link de folha de estilo ao layout uma vez e cada página o seleciona automaticamente, nenhum outro arquivo precisa ser tocado.
As Paredes, Resumidamente
Olhando para trás, para o processo acima, os pontos de atrito reais foram:
- Um tÃtulo em branco travando o aplicativo (Etapa 3), o banco de dados aplicando uma regra na camada errada.
- **O mesmo acidente escondido em **
update()(Etapa 4), a mesma correção, necessitando apenas do sequenciamento correto. - Clique na vinculação do modelo de rota (Etapa 4), uma vez que comparei um método que o usava com outro que não o usava.
- Entrada antiga parecendo que funcionou antes de realmente funcionar (Etapa 5), ​​dois mecanismos diferentes que produziram resultados de aparência idêntica.
- **Hesitando antes **
Route::resource()(Passo 6), medo de uma mudança que se revelou segura. - Quatro shells de páginas duplicados (Etapa 7), corrigido quando a repetição se tornou irritante o suficiente para ser notada.
Nada disso foi individualmente difÃcil. O que foi difÃcil foi perceber, naquele momento, que um bug ou uma hesitação apontava para um conceito faltante, não para uma linha de código faltante.
Para onde vai o Tiny Journal a partir daqui
Algumas próximas etapas óbvias se você estiver avançando:
- Mensagens instantâneas após criar, atualizar e excluir, para que o usuário receba confirmação em vez de um redirecionamento silencioso
- Regras de validação mais fortescomprimentos mÃnimos, limites de caracteres, em vez de apenas
required - Exclusões suavesentão “excluir” não significa desaparecer permanentemente
Se você está aprendendo Laravel agora: construa algo pequeno, quebre-o de propósito e leia o erro em vez de colá-lo imediatamente em uma barra de pesquisa. A estrutura geralmente já tem uma resposta para qualquer repetição ou fragilidade que você esteja sentindo. Você só precisa bater na parede primeiro para saber qual pergunta fazer.




